using System;
using Org.BouncyCastle.Math;
namespace ch.ethz.ssh2.crypto
{
	
	/// <summary> SimpleDERReader.
	/// 
	/// </summary>
	/// <author>  Christian Plattner
	/// </author>
	/// <version>  2.50, 03/15/10
	/// </version>
	public class SimpleDERReader
	{
		internal byte[] buffer;
		internal int pos;
		internal int count;
		
		public SimpleDERReader(byte[] b)
		{
			resetInput(b);
		}
		
		public SimpleDERReader(byte[] b, int off, int len)
		{
			resetInput(b, off, len);
		}
		
		public virtual void  resetInput(byte[] b)
		{
			resetInput(b, 0, b.Length);
		}
		
		public virtual void  resetInput(byte[] b, int off, int len)
		{
			buffer = b;
			pos = off;
			count = len;
		}
		
		private byte readByte()
		{
			if (count <= 0)
				throw new System.IO.IOException("DER byte array: out of data");
			count--;
			return buffer[pos++];
		}
		
		private byte[] readBytes(int len)
		{
			if (len > count)
				throw new System.IO.IOException("DER byte array: out of data");
			
			byte[] b = new byte[len];
			
			Array.Copy(buffer, pos, b, 0, len);
			
			pos += len;
			count -= len;
			
			return b;
		}
		
		public virtual int available()
		{
			return count;
		}
		
		private int readLength()
		{
			int len = readByte() & 0xff;
			
			if ((len & 0x80) == 0)
				return len;
			
			int remain = len & 0x7F;
			
			if (remain == 0)
				return - 1;
			
			len = 0;
			
			while (remain > 0)
			{
				len = len << 8;
				len = len | (readByte() & 0xff);
				remain--;
			}
			
			return len;
		}
		
		public virtual int ignoreNextObject()
		{
			int type = readByte() & 0xff;
			
			int len = readLength();
			
			if ((len < 0) || len > available())
				throw new System.IO.IOException("Illegal len in DER object (" + len + ")");
			
			readBytes(len);
			
			return type;
		}
		
		public virtual BigInteger readInt()
		{
			int type = readByte() & 0xff;
			
			if (type != 0x02)
				throw new System.IO.IOException("Expected DER Integer, but found type " + type);
			
			int len = readLength();
			
			if ((len < 0) || len > available())
				throw new System.IO.IOException("Illegal len in DER object (" + len + ")");
			
			byte[] b = readBytes(len);

            BigInteger bi = new BigInteger(b);
			
			return bi;
		}

        public virtual byte[] readSequenceAsByteArray()
		{
			int type = readByte() & 0xff;
			
			if (type != 0x30)
				throw new System.IO.IOException("Expected DER Sequence, but found type " + type);
			
			int len = readLength();
			
			if ((len < 0) || len > available())
				throw new System.IO.IOException("Illegal len in DER object (" + len + ")");
			
			byte[] b = readBytes(len);
			
			return b;
		}
		
		public virtual byte[] readOctetString()
		{
			int type = readByte() & 0xff;
			
			if (type != 0x04)
				throw new System.IO.IOException("Expected DER Octetstring, but found type " + type);
			
			int len = readLength();
			
			if ((len < 0) || len > available())
				throw new System.IO.IOException("Illegal len in DER object (" + len + ")");
			
			byte[] b = readBytes(len);
			
			return b;
		}
	}
}